//
// Created by hjie on 23-7-23.
//

#include "aac_frame.h"
#include "aac_attr.h"

AACFrame::AACFrame()
{
    m_sync_word = 0x0fff;
}

bool AACFrame::AdtsFixedHeader(const uint8_t *buffer, int length, int &index)
{
    if (length < 4)
    {
        return false;
    }
    index = 0;
    // syncword 12bit
    // id 1bit
    // layer 2bit
    // protection_absent 1bit
    {
        const uint8_t * ptr = buffer;
        uint16_t sync_word = *(ptr);
        sync_word = (sync_word << 4) | ((*(ptr + 1) >> 4) & 0b1111);
        if (m_sync_word  != sync_word)
        {
            printf("no find sync word and %d.\n", sync_word);
            return false;
        }
        m_id    = (*(ptr+1) & 0x08);
        m_layer = (*(ptr+1) & 0x06);
        m_protection_absent = (*(ptr+1) & 0x01);
        index += 2;
    }
    // profile 2bit
    // sampling frequency index 4bit
    // private_bit 1bit
    // channel_configuration 3bit
    // original copy 1bit
    // home  1bit
    {
        const uint8_t * ptr = buffer + index;
        m_profile = *(ptr) >> 6;
        m_sampling_frequency_index = (*(ptr) & 0x3c) >> 2;
        m_private_bit = (*(ptr) & 0b00000010) >> 1;
        m_channel_configuration = ((*(ptr) & 0x0100) | (*(ptr + 1) & 0x00c0)) >> 6;
        m_origin_copy = *(ptr + 1) & 0b00100000;
        m_home        = *(ptr + 1) & 0b00010000;
        index += 1;
    }
    return true;
}

bool AACFrame::AdtsVariableHeader(const uint8_t *buffer, int length, int &index)
{
    if (length < 4)
    {
        return false;
    }
    index = 0;
    // copyright identification bit 1bit
    // copyright identification start 1bit
    // aac frame length 13bit
    // adts buffer fullness
    // number of raw data blocks in frame
    {
        const uint8_t * ptr = buffer;
        m_copyright_identification_bit   = *(ptr) & 0b00001000;
        m_copyright_identification_start = *(ptr) & 0b00000100;
        // 2 + 8 + 3
        m_aac_frame_length = ((*(ptr) & 0x0003) << 11);
        m_aac_frame_length = m_aac_frame_length | ((*(ptr + 1) & 0x00ff));
        m_aac_frame_length = m_aac_frame_length << 3;
        m_aac_frame_length = m_aac_frame_length | (((*(ptr + 2)) & 0x00e0) >> 5);
        // 5 + 6
        m_adts_buffer_fullness = ((*(ptr + 2) & 0x1f) << 6) | ((*(ptr + 3) & 0xfc) >> 2);
        // 2
        m_number_of_raw_data_blocks_in_frame = (*(ptr + 3) & 0x03);
        index += (m_protection_absent == 1 ? 4 : 6);

        m_es_length = m_aac_frame_length - (m_protection_absent == 1 ? 7 : 9);
        m_es_data.resize(m_es_length);
        memcpy(&(*m_es_data.begin()), buffer + index, m_es_length);
        index += m_es_length;
    }
    return false;
}

void AACFrame::DumpFixedHeader()
{
    printf("sync word : %d\tid : %s\tlayer : %d\tprotection_absent : %d.\n",
           m_sync_word,
           AACAttr::GetId(m_id).c_str(),
           m_layer,
           m_protection_absent);
    printf("profile : %s\tsampling frequency index : %d b/s\tprivate bit : %d\tchannel_configuration : %s.\n",
           AACAttr::GetAudioObjectType(m_profile + 1).c_str(),
           AACAttr::GetSampleFrequencyIndex(m_sampling_frequency_index),
           m_private_bit,
           AACAttr::GetChannelConfiguration(m_channel_configuration).c_str());
}

void AACFrame::DumpVariableHeader()
{
    printf("copyright identification bit : %d\t"
           "copyright identification start : %d\t"
           "aac frame length : %d\t"
           "adts buffer fullness : %d\t"
           "number of raw data blocks in frame : %d\t"
           "es_length : %d\t"
           "es_length equal es data : %d.\n",
           m_copyright_identification_bit,
           m_copyright_identification_start,
           m_aac_frame_length,
           m_adts_buffer_fullness,
           m_number_of_raw_data_blocks_in_frame,
           m_es_length,
           (m_es_data.size() == m_es_length));
}
